package com.dispacher.processor.impl;

import java.lang.reflect.Field;
import java.util.List;

import com.dispacher.config.GlobalConfig;
import com.dispacher.context.ContextHolder;
import com.dispacher.context.RequestContext;
import com.dispacher.context.ResponseContext;
import com.dispacher.log.LogFactory;
import com.dispacher.log.Logger;
import com.dispacher.processor.Processor;
import com.dispacher.springsupport.SpringSwitch;
import com.dispacher.util.ClassUtil;
import com.dispacher.util.MethodUtil;
import com.dispacher.util.PropertiesUtil;

public class DefaultProcessor implements Processor {

	private static Logger log = LogFactory.getDefaultLog();

	private String url = null;

	public void setRequestURL(String url) {
		this.url = url;
	}

	/**
	 * 
	 */
	public String doProcess() {
		String[] patterns = url.split("/");
		Object instance = findInstance(patterns[0]);
		Object returnResult = MethodUtil.invoke(patterns[1], instance, null);
		reInitresponse(instance);
		if (returnResult instanceof String) {
			log.log("with the return url : " + returnResult);
			return String.valueOf(returnResult);
		}
		if (returnResult != null) {
			ResponseContext.responseJson(returnResult);
		}
		return null;
	}

	public void reInitresponse(Object instance) {
		List<Field> props = PropertiesUtil.getCachedFields(instance.getClass());
		for (Field field : props) {
			Object reInitObj;
			try {
				field.setAccessible(true);
				reInitObj = field.get(instance);
				ResponseContext.setReturnAttr(field.getName(), reInitObj);
			} catch (IllegalArgumentException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 通过url跟后台默认的配置寻找相应的地址, 如果在提交的form属性里面使用了namespace的定义方式将进行属性的绑定
	 * 
	 * @param url
	 * @return
	 */
	private Object findInstance(String url) {
		String[] urlsuffixs = GlobalConfig.getUrlSuffix();
		for (String urlsuffix : urlsuffixs) {
			Object result = null;
			result = ClassUtil.findInstance(urlsuffix + "." + url);
			if (result != null) {
				// bind parameters
				try {
					initObject(result);
				} catch (IllegalArgumentException e) {
					e.printStackTrace();
				} catch (IllegalAccessException e) {
					e.printStackTrace();
				}
				// bind spring
				if (isSpringNeeded()) {
					PropertiesUtil.initSpringField(result);
				}
				return result;
			}
		}
		throw new RuntimeException("Can't find one valid class for your url, please check the configure.properties");
	}

	/**
	 * @param <T>
	 * @throws IllegalAccessException
	 * @throws IllegalArgumentException
	 * 
	 */
	private <T> void initObject(Object obj) throws IllegalArgumentException, IllegalAccessException {
		// bind parameters
		List<Field> props = PropertiesUtil.getCachedFields(obj.getClass());
		for (Field field : props) {
			if (field.get(obj) != null) {
				continue;
			}
			field.setAccessible(true);
			Object parameter = RequestContext.getParameter(field.getName());
			if (field.getGenericType().equals(String.class)) {
				if (parameter != null)
					field.set(obj, String.valueOf(parameter));
			} else if (field.getGenericType().equals(int.class) || field.getGenericType().equals(Integer.class)) {
				if (parameter != null)
					field.set(obj, Integer.valueOf(String.valueOf(parameter)));
			} else if (field.getGenericType().equals(long.class) || field.getGenericType().equals(Long.class)) {
				if (parameter != null)
					field.set(obj, Long.valueOf(String.valueOf(parameter)));
			} else if (field.getGenericType().equals(double.class) || field.getGenericType().equals(Double.class)) {
				if (parameter != null)
					field.set(obj, Long.valueOf(String.valueOf(parameter)));
			} else {
				T result = ContextHolder.initFromTheRequest(field.getName(), (Class<T>) field.getGenericType());
				field.set(obj, result);
			}
			// field.setAccessible(false);
		}
	}

	private static boolean isSpringNeeded = false;

	private static boolean isSpringChecked = false;

	public boolean isSpringNeeded() {
		if (!isSpringChecked) {
			isSpringNeeded = SpringSwitch.isSpringSupport();
			isSpringChecked = true;
		}
		return isSpringNeeded;
	}

}
